﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace mp3Transfer
{
    // Константы, используемые в программе
    public class Const
    {
        // Перевод байт в мегабайты
        public static Double B2MB = (Double)1/(1024*1024);
        public static String[] GENRE_LIST = {
                                    "Blues",
                                    "Classic Rock",
                                    "Country",
                                    "Dance",
                                    "Disco",
                                    "Funk",
                                    "Grunge",
                                    "Hip-Hop",
                                    "Jazz",
                                    "Metal",
                                    "New Age",
                                    "Oldies",
                                    "Other",
                                    "Pop",
                                    "R&B",
                                    "Rap",
                                    "Reggae",
                                    "Rock",
                                    "Techno",
                                    "Industrial",
                                    "Alternative",
                                    "Ska",
                                    "Death Metal",
                                    "Pranks",
                                    "Soundtrack",
                                    "Euro-Techno",
                                    "Ambient",
                                    "Trip-Hop",
                                    "Vocal",
                                    "Jazz+Funk",
                                    "Fusion",
                                    "Trance",
                                    "Classical",
                                    "Instrumental",
                                    "Acid",
                                    "House",
                                    "Game",
                                    "Sound Clip",
                                    "Gospel",
                                    "Noise",
                                    "AlternRock",
                                    "Bass",
                                    "Soul",
                                    "Punk",
                                    "Space",
                                    "Meditative",
                                    "Instrumental Pop",
                                    "Instrumental Rock",
                                    "Ethnic",
                                    "Gothic",
                                    "Darkwave",
                                    "Techno-Industrial",
                                    "Electronic",
                                    "Pop-Folk",
                                    "Eurodance",
                                    "Dream",
                                    "Southern Rock",
                                    "Comedy",
                                    "Cult",
                                    "Gangsta",
                                    "Top 40",
                                    "Christian Rap",
                                    "Pop/Funk",
                                    "Jungle",
                                    "Native American",
                                    "Cabaret",
                                    "New Wave",
                                    "Psychadelic",
                                    "Rave",
                                    "Showtunes",
                                    "Trailer",
                                    "Lo-Fi",
                                    "Tribal",
                                    "Acid Punk",
                                    "Acid Jazz",
                                    "Polka",
                                    "Retro",
                                    "Musical",
                                    "Rock & Roll",
                                    "Hard Rock",
                                    "Folk",
                                    "Folk-Rock",
                                    "National Folk",
                                    "Swing",
                                    "Fast Fusion",
                                    "Bebob",
                                    "Latin",
                                    "Revival",
                                    "Celtic",
                                    "Bluegrass",
                                    "Avantgarde",
                                    "Gothic Rock",
                                    "Progressive Rock",
                                    "Psychedelic Rock",
                                    "Symphonic Rock",
                                    "Slow Rock",
                                    "Big Band",
                                    "Chorus",
                                    "Easy Listening",
                                    "Acoustic",
                                    "Humour",
                                    "Speech",
                                    "Chanson",
                                    "Opera",
                                    "Chamber Music",
                                    "Sonata",
                                    "Symphony",
                                    "Booty Bass",
                                    "Primus",
                                    "Porn Groove",
                                    "Satire",
                                    "Slow Jam",
                                    "Club",
                                    "Tango",
                                    "Samba",
                                    "Folklore",
                                    "Ballad",
                                    "Power Ballad",
                                    "Rhythmic Soul",
                                    "Freestyle",
                                    "Duet",
                                    "Punk Rock",
                                    "Drum Solo",
                                    "A capella",
                                    "Euro-House",
                                    "Dance Hall"
                                   };
    }

    // Файл [песни?]
    public class Song
    {
        // Стандартный конструктор
        public Song(String _name)
        {
            name = _name;
        }
        // Полный путь к файлу
        String name;
        public String Name
        {
            get
            {
                return name;
            }
        }
    }

    // Файл [песни?] в кэше
    public class CacheSong
    {
        // Стандартный конструктор
        public CacheSong()
        {
            isTaged = new Boolean[2];
        }

        // Полный путь к файлу
        String fullName;
        String name;
        Double size;
        Int16 genre;
        Int16 rating;
        String year;
        String artist;
        String album;
        String songName;
        String modifyDate;
        Boolean[] isTaged;

        public String FullName
        {
            get
            {
                return fullName;
            }
            set
            {
                fullName = value;
            }
        }
        public String Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        public Double Size
        {
            get
            {
                return size;
            }
            set
            {
                size = value;
            }
        }
        public Int16 Genre
        {
            get
            {
                return genre;
            }
            set
            {
                genre = value;
            }
        }
        public Int16 Rating
        {
            get
            {
                return rating;
            }
            set
            {
                rating = value;
            }
        }
        public String Artist
        {
            get
            {
                return artist;
            }
            set
            {
                artist = value;
            }
        }
        public String Album
        {
            get
            {
                return album;
            }
            set
            {
                album = value;
            }
        }
        public String Year
        {
            get
            {
                return year;
            }
            set
            {
                year = value;
            }
        }
        public String SongName
        {
            get
            {
                return songName;
            }
            set
            {
                songName = value;
            }
        }
        public String ModifyDate
        {
            get
            {
                return modifyDate;
            }
            set
            {
                modifyDate = value;
            }
        }
        public Boolean IsTagedV1
        {
            get
            {
                return isTaged[0];
            }
            set
            {
                isTaged[0] = value;
            }
        }
        public Boolean IsTagedV2
        {
            get
            {
                return isTaged[1];
            }
            set
            {
                isTaged[1] = value;
            }
        }
    }

    // Общий список файлов
    public class FList
    {
        // Конструктор
        public FList()
        {
            songs = new List<Song>();
            cacheSongs = new List<CacheSong>();
            config = new Config();
            config.ReadConfig();
        }
        
        // Список файлов. public? добавить возможность перебора файлов 
        // без прямого доступа. итератор?
        public List<Song> songs;
        public List<CacheSong> cacheSongs;
        Config config;

        // Добавить новый элемент
        public Int16 AddSong(Song _song)
        {
            if (_song != null && !_song.Name.Equals(""))
            {
                songs.Add(_song);
                return 0;
            }
            return 1;
        }
        // Получить элемент по индексу
        public Song GetSong(Int32 _index)
        {
            if (_index >= 0 && _index < songs.Count)
            {
                return songs[_index];
            }
            return null;
        }
        // Удалить элемент по индексу
        public Int16 DeleteSong(Int32 _index)
        {
            if (_index >= 0 && _index < songs.Count)
            {
                songs.Remove(songs[_index]);
                return 0;
            }
            return 1;
        }
        // Получить и удалить(извлечь) элемент по индексу
        public Song GetNDelSong(Int32 _index)
        {
            Song tempSong = GetSong(_index);
            if (tempSong != null)
            {
                if (DeleteSong(_index) == 0)
                {
                    return tempSong;
                }
            }
            return null;
        }
        // 
        void SearchInDir(String _pathToDir, String _template, Boolean _recursive)
        {
            try
            {
                if (_recursive)
                {
                    String[] directories = Directory.GetDirectories(_pathToDir);

                    foreach (String tempDir in directories)
                    {
                        SearchInDir(tempDir, _template, true);
                    }
                }

                List<String> filesInDir = new List<String>();
                Char[] split = {';'};
                String[] miniTemplates = _template.Split(split);
                foreach (String tempTemplate in miniTemplates)
                {
                    String[] tempFilesInDir = Directory.GetFiles(_pathToDir, tempTemplate);
                    filesInDir.AddRange(tempFilesInDir);
                }
                
                foreach (String tempFile in filesInDir)
                {
                    songs.Add(new Song(tempFile));
                    

                    //Console.WriteLine("{0}", tempFile);

                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Error in SearchInDir: {0}", e.Message);
            }
        }
        // 
        public void ScanForFiles()
        {
            Console.WriteLine("Start searching in dirs");
            for (Int16 i = 0; i < config.dirs.Count; i++)
            {
                SearchInDir(config.dirs[i].Path, config.dirs[i].Template, config.dirs[i].Recursive);
            }
            Console.WriteLine("End searching in dirs\n");
        }
        // 
        public void CreateCacheFile()
        {
            try
            {
                Console.WriteLine("Start creating cache file");
                FileStream fCacheStream = new FileStream(config.PathCacheFile, FileMode.Create, FileAccess.Write);
                StreamWriter fCacheWriter = new StreamWriter(fCacheStream);
                Int64 tempI = 0;
                foreach (Song tempSong in songs)
                {
                    FileStream fTempStream = new FileStream(tempSong.Name, FileMode.Open, FileAccess.Read);

                    FileInfo tempFileInfo = new FileInfo(tempSong.Name);
                    CacheSong tempCacheSong = new CacheSong();
                    tempCacheSong.FullName = tempSong.Name;
                    tempCacheSong.Name = tempFileInfo.Name;
                    tempCacheSong.Rating = 0;
                    tempCacheSong.Size = (Double)tempFileInfo.Length * Const.B2MB;
                    
                    // Если есть теги
                    fTempStream.Position = tempFileInfo.Length - 128;
                    StreamReader fTempReader = new StreamReader(fTempStream);
                    String tags = fTempReader.ReadToEnd();
                    String tempNameSong = "NoSongName";
                    String tempArtist = "NoArtist";
                    String tempAlbum = "NoAlbum";
                    String tempYear = "NoYear";
                    String tempComment = "";
                    Int16 tagGenre = 12;
                    Boolean tempIsTagedV1 = false;
                    Boolean tempIsTagedV2 = false;

                    if (tags.Substring(0, 3).Equals("TAG"))
                    {
                        Char[] trimChars = { '\0' };
                        tempNameSong = tags.Substring(3, 30).TrimEnd(trimChars);
                        tempArtist = tags.Substring(33, 30).TrimEnd(trimChars);
                        tempAlbum = tags.Substring(63, 30).TrimEnd(trimChars);
                        tempYear = tags.Substring(93, 4).TrimEnd(trimChars);
                        tempComment = tags.Substring(97, 30).TrimEnd(trimChars);
                        tagGenre = (Int16)tags.Substring(127, 1)[0];
                        tempIsTagedV1 = true;

                        //Если жанр в теге почему-то вне диапазона - меняем его на 12 - Other
                        tagGenre = (tagGenre < 0 || tagGenre > 125) ? (Int16)12 : tagGenre;

                        Console.WriteLine("TAG");
                    }

                    tempCacheSong.SongName = tempNameSong;
                    tempCacheSong.Artist = tempArtist;
                    tempCacheSong.Album = tempAlbum;
                    tempCacheSong.Genre = tagGenre;
                    tempCacheSong.Year = tempYear;
                    tempCacheSong.ModifyDate = tempFileInfo.LastWriteTime.ToString("dd.MM.yyyy-hh:mm:ss");
                    tempCacheSong.IsTagedV1 = tempIsTagedV1;
                    tempCacheSong.IsTagedV2 = tempIsTagedV2;

                    fTempReader.Close();
                    fTempStream.Close();

                    fCacheWriter.WriteLine(tempCacheSong.FullName + "|" + tempCacheSong.SongName + "|" + 
                        tempCacheSong.Size.ToString("F02") + "|" + tempCacheSong.Artist + "|" + 
                        tempCacheSong.Album + "|" + tempCacheSong.Year + "|" + tempCacheSong.Genre + "|" + 
                        tempCacheSong.Rating + "|" + tempCacheSong.ModifyDate);

                    Console.WriteLine("{0} " + tempCacheSong.FullName, tempI++);

                    cacheSongs.Add(tempCacheSong);
                }

                fCacheWriter.Close();
                fCacheStream.Close();
                Console.WriteLine("End creating cache file\n");
            }
            catch (Exception e)
            {
                System.Console.WriteLine("CreateCacheFile Error: {0}", e.Message);
            }
        }
        // 
        public void Synchronize(Boolean _toDisk)
        {
            try
            {
                if (_toDisk)
                {
                    Console.WriteLine("Start synchronize to disk");
                    FileStream fCacheStream = new FileStream(config.PathCacheFile, FileMode.Create, FileAccess.Write);
                    StreamWriter fCacheWriter = new StreamWriter(fCacheStream);
                    
                    foreach (CacheSong tempCacheSong in cacheSongs)
                    {
                        fCacheWriter.WriteLine(tempCacheSong.FullName + "|" + tempCacheSong.SongName + "|" +
                            tempCacheSong.Size.ToString("F02") + "|" + tempCacheSong.Artist + "|" +
                            tempCacheSong.Album + "|" + tempCacheSong.Year + "|" + tempCacheSong.Genre + "|" +
                            tempCacheSong.Rating + "|" + tempCacheSong.ModifyDate);

                    }

                    fCacheWriter.Close();
                    fCacheStream.Close();
                    Console.WriteLine("End synchronize to disk");
                }
                else
                {
                    Console.WriteLine("Start synchronize from disk");
                    FileStream fCacheStream = new FileStream(config.PathCacheFile, FileMode.Open, FileAccess.Read);
                    StreamReader fCacheReader = new StreamReader(fCacheStream);

                    String fromCacheFile;
                    Char[] separator = {'|'};
                    Int16 i = 0;
                    cacheSongs.Clear();
                    while ((fromCacheFile = fCacheReader.ReadLine()) != null)
                    {
                        String[] fromCacheFileArr = fromCacheFile.Split(separator);
                        
                        CacheSong tempCacheSong = new CacheSong();
                        tempCacheSong.FullName = fromCacheFileArr[0];
                        tempCacheSong.Name = (new FileInfo(fromCacheFileArr[0])).Name;
                        tempCacheSong.Rating = Int16.Parse(fromCacheFileArr[7]);
                        tempCacheSong.Size = Double.Parse(fromCacheFileArr[2]);
                        tempCacheSong.SongName = fromCacheFileArr[1];
                        tempCacheSong.Artist = fromCacheFileArr[3];
                        tempCacheSong.Album = fromCacheFileArr[4];
                        tempCacheSong.Year = fromCacheFileArr[5];
                        tempCacheSong.Genre = Int16.Parse(fromCacheFileArr[6]);
                        tempCacheSong.ModifyDate = fromCacheFileArr[8];

                        /*Console.WriteLine("FullName === {0}", fromCacheFileArr[0]);
                        Console.WriteLine("Name ======= {0}", (new FileInfo(fromCacheFileArr[0])).Name);
                        Console.WriteLine("Rating ===== {0}", Int16.Parse(fromCacheFileArr[7]));
                        Console.WriteLine("Size ======= {0}", Double.Parse(fromCacheFileArr[2]));
                        Console.WriteLine("SongName  == {0}", fromCacheFileArr[1]);
                        Console.WriteLine("Artist ===== {0}", fromCacheFileArr[3]);
                        Console.WriteLine("Album ====== {0}", fromCacheFileArr[4]);
                        Console.WriteLine("Year ======= {0}", fromCacheFileArr[5]);
                        Console.WriteLine("Genre ====== {0}", fromCacheFileArr[6]);//Int16.Parse(fromCacheFileArr[5]));
                        //Console.WriteLine("ModifyDate = {0}", fromCacheFileArr[8]);*/

                        cacheSongs.Add(tempCacheSong);

                        /*Console.Write("{0}. ", i++);
                        foreach (String tmpStr in fromCacheFileArr)
                        {
                            Console.Write(tmpStr + "|");
                        }
                        Console.WriteLine();*/
                    }

                    fCacheReader.Close();
                    fCacheStream.Close();
                    Console.WriteLine("End synchronize from disk");
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Synchronize Error: {0}", e.Message);
            }
        }
        // 
        public void CreateTags(String _dir, String _artist, String _album, String _year, Int16 _genre)
        {
            Console.WriteLine("Strart creating tags");
            foreach (CacheSong tmpSong in cacheSongs)
            {
                if (System.Text.RegularExpressions.Regex.IsMatch(tmpSong.FullName, _dir))
                {
                    Console.WriteLine(tmpSong.FullName);
                    if (!_artist.Equals("")) tmpSong.Artist = _artist;
                    if (!_album.Equals("")) tmpSong.Album = _album;
                    if (!_year.Equals("")) tmpSong.Year = _year;
                    if (_genre != 0) tmpSong.Genre = _genre;
                }
            }
            Console.WriteLine("End creating tags");
        }
        // 
        public void PrintCache(Int16 _flags)
        {
            /*  0000000001 = 1    = SongName
             *  0000000010 = 2    = Artist 
             *  0000000100 = 4    = Album 
             *  0000001000 = 8    = Genre
             *  0000010000 = 16   = Year
             *  0000100000 = 32   = Size
             *  0001000000 = 64   = Rating
             */

            Console.WriteLine("Strart printing list");
            Int32 i = 0;
            foreach (CacheSong tmpSong in cacheSongs)
            {
                Console.Write("{0}. ", i++);
                if ((_flags & 1   ) == 1   ) Console.Write(tmpSong.SongName+" - ");
                if ((_flags & 2   ) == 2   ) Console.Write(tmpSong.Artist + " - ");
                if ((_flags & 4   ) == 4   ) Console.Write(tmpSong.Album + " - ");
                if ((_flags & 16  ) == 16  ) Console.Write(tmpSong.Year + " - ");
                if ((_flags & 8   ) == 8   ) Console.Write(Const.GENRE_LIST[tmpSong.Genre] + " - ");
                if ((_flags & 32  ) == 32  ) Console.Write(tmpSong.Size + " - ");
                if ((_flags & 64  ) == 64  ) Console.Write(tmpSong.Rating + " - ");
                Console.WriteLine();
            }
            Console.WriteLine("End printing list");
        }
        // 
        public void ChangeDirs(String _rootDir)
        {
            try
            {
                Console.WriteLine("Strart ChangeDirs");

                DirectoryInfo dirInfo = new DirectoryInfo(_rootDir);
                if (!dirInfo.Exists)
                {
                    Console.WriteLine("root directory _rootDir does not exosts");
                    return;
                }

                foreach (CacheSong tmpSong in cacheSongs)
                {
                    String pathToDir = _rootDir + @"\" + Const.GENRE_LIST[tmpSong.Genre] + @"\" + tmpSong.Artist + @"\" + 
                        tmpSong.Album + " - " + tmpSong.Year;

                    Console.WriteLine(pathToDir);
                    if (!(new DirectoryInfo(pathToDir)).Exists)
                    {
                        Directory.CreateDirectory(pathToDir);
                    }
                    if ((new FileInfo(pathToDir+@"\"+tmpSong.Name)).Exists)
                    {
                        Console.WriteLine("File {0} already exists!", pathToDir + @"\" + tmpSong.Name);
                        continue;
                    }
                    (new FileInfo(tmpSong.FullName)).CopyTo(pathToDir + @"\" + tmpSong.Name);
                }

                Console.WriteLine("End ChangeDirs");
            }
            catch (Exception e)
            {
                System.Console.WriteLine("ChangeDirs Error: {0}", e.Message);
            }
        }
        // 
        public void FlushCache()
        {
            try
            {
                Console.WriteLine("Strart flushing list");
                foreach (CacheSong tmpSong in cacheSongs)
                {
                    if (tmpSong.IsTagedV1 || true)
                    {
                        if (true)
                        {
                            FileStream fSongStream = new FileStream(tmpSong.FullName, FileMode.Open, FileAccess.Write);
                            if (tmpSong.IsTagedV1) fSongStream.Position = fSongStream.Length-128;
                            else fSongStream.Position = fSongStream.Length;
                            StreamWriter fSongWriter = new StreamWriter(fSongStream);

                            String tags = "TAG";
                            tags += (tmpSong.SongName.Length > 30) ? tmpSong.SongName.Substring(0, 30) : tmpSong.SongName;
                            for (Int16 i = 0; i < 30 - tmpSong.SongName.Length; i++) tags += '\0';
                            
                            tags += (tmpSong.Artist.Length > 30) ? tmpSong.Artist.Substring(0, 30) : tmpSong.Artist;
                            for (Int16 i = 0; i < 30 - tmpSong.Artist.Length; i++) tags += '\0';

                            tags += (tmpSong.Album.Length > 30) ? tmpSong.Album.Substring(0, 30) : tmpSong.Album;
                            for (Int16 i = 0; i < 30 - tmpSong.Album.Length; i++) tags += '\0';
                            
                            tags += (tmpSong.Year.Length > 4) ? tmpSong.Year.Substring(0, 4) : tmpSong.Year;
                            for (Int16 i = 0; i < 4 - tmpSong.Year.Length; i++) tags += '\0';
                            
                            for (Int16 i = 0; i < 30; i++) tags += '\0';
                            
                            tags += (Char)tmpSong.Genre;

                            //Console.WriteLine(tags);
                            fSongWriter.Write(tags);

                            fSongWriter.Close();
                            fSongStream.Close();
                        }
                    }
                    else
                    {
                    }
                }
                Console.WriteLine("End flushing list");
            }
            catch (Exception e)
            {
                System.Console.WriteLine("FlushCache Error: {0}", e.Message);
            }
        }
    }

    // Статистика
    public class Statistics
    {
        public Statistics()
        {
        }

        Double totalSize;
        Double averageSize;
        Int64 totalSongCount;
        Int64 totalDirCount;

        // 
        public Double GetTotalSize(List<CacheSong> _songs)
        {
            Double tmpSize = 0;
            foreach (CacheSong tempSong in _songs)
            {
                tmpSize += tempSong.Size;
            }
            totalSize = tmpSize;
            return totalSize;
        }
        // 
        public Double GetAverageSize(List<CacheSong> _songs)
        {
            Double tmpSize = 0;
            Int64 tmpCount = 0;
            foreach (CacheSong tempSong in _songs)
            {
                tmpSize += tempSong.Size;
                tmpCount++;
            }
            if (tmpCount != 0)
            {
                averageSize = tmpSize / tmpCount;
                return averageSize;
            }
            return 0;
        }
        // 
        public Int64 GetTotalSongCount(List<CacheSong> _songs)
        {
            totalSongCount = _songs.Count;
            return totalSongCount;
        }
        // 
        public Int64 GetTotalDirCount(List<CacheSong> _songs)
        {
            List<String> tmpDirList = new List<String>();
            foreach (CacheSong tempSong in _songs)
            {
                FileInfo fi = new FileInfo(tempSong.Name);
                //fi.DirectoryName;
             }
            return 0;
        }
    }

    public class Config
    {
        public Config()
        {
            dirs = new List<Dir>();
            pathCacheFile = "";
            pathConfigFile = @"../../config.xml";
            pathDirsList = "";
        }
        public Config(string _pathConfigFile)
        {
            pathConfigFile = _pathConfigFile;
            dirs = new List<Dir>();
            pathCacheFile = "";
            pathDirsList = "";
        }

        public List<Dir> dirs;
        String pathCacheFile;
        String pathConfigFile;
        String pathDirsList;

        public String PathCacheFile
        {
            get
            {
                return pathCacheFile;
            }
        }
        public String PathConfigFile
        {
            get
            {
                return pathConfigFile;
            }
        }
        public String PathDirsList
        {
            get
            {
                return pathDirsList;
            }
        }

        public Int16 ReadConfig()
        {
            try
            {
                System.Xml.XmlTextReader config = new System.Xml.XmlTextReader(pathConfigFile);
                Int16 i = 0;
                while (config.Read())
                {
                    if (config.NodeType == System.Xml.XmlNodeType.Element)
                    {
                        config.Read();
                        if (i == 1)
                        {
                            Console.WriteLine("Path to dirs list file: {0}", config.Value);
                            pathDirsList = config.Value;
                        }
                        else if (i == 2)
                        {
                            Console.WriteLine("Path to cache file: {0}", config.Value);
                            pathCacheFile = config.Value;
                        }
                        i++;
                    }
                }

                System.Xml.XPath.XPathDocument xpd = new System.Xml.XPath.XPathDocument(pathDirsList);
                System.Xml.XPath.XPathNavigator xpn = xpd.CreateNavigator();

                List<String> path = new List<String>();
                List<String> template = new List<String>();
                List<Int16> rec = new List<Int16>();

                System.Xml.XPath.XPathNodeIterator xpi = xpn.Select("DIRSLIST/DIR/PATH");
                while (xpi.MoveNext())
                {
                    //Console.WriteLine(xpi.Current);
                    path.Add(xpi.Current.ToString());
                }

                System.Xml.XPath.XPathExpression xpe = xpn.Compile("DIRSLIST/DIR/RECURSIVE");
                System.Xml.XPath.XPathNodeIterator xpi2 = xpn.Select(xpe);
                while (xpi2.MoveNext())
                {
                    //Console.WriteLine(xpi2.Current);
                    rec.Add(Int16.Parse(xpi2.Current.ToString()));
                }

                System.Xml.XPath.XPathExpression xpe2 = xpn.Compile("DIRSLIST/DIR/TEMPLATE");
                System.Xml.XPath.XPathNodeIterator xpi3 = xpn.Select(xpe2);
                while (xpi3.MoveNext())
                {
                    //Console.WriteLine(xpi3.Current);
                    template.Add(xpi3.Current.ToString());
                }

                Console.WriteLine("\nDirs list: ");
                for (i = 0; i < path.Count; i++)
                {
                    Console.WriteLine("{0} - '{1}' - {2}recursive", path[i], template[i], (rec[i] == 1) ? "" : "not ");
                    dirs.Add(new Dir(path[i], template[i], (rec[i] == 1) ? true : false));
                }

                return 0;
            }
            catch (Exception e)
            {
                System.Console.WriteLine("ReadConfig Error: {0}", e.Message);
                return 1;
            }
        }
    }

    public class Dir
    {
        public Dir(String _path, String _template, Boolean _recursive)
        {
            path = _path;
            template = _template;
            recursive = _recursive;
        }

        // 
        String path;
        // 
        String template;
        // 
        Boolean recursive;

        // 
        public String Path
        {
            get
            {
                return path;
            }
        }
        // 
        public String Template
        {
            get
            {
                return template;
            }
        }
        // 
        public Boolean Recursive
        {
            get
            {
                return recursive;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("************** start **************\n");

                FList list = new FList();

                list.ScanForFiles(); //1
                list.CreateCacheFile(); //2
                list.PrintCache(1 + 2 + 4 + 16);
                /*list.CreateTags(@"Carry Me Over", "Avantasia", "Carry Me Over - Single", "2008", 0); //3
                list.PrintCache(1 + 2 + 4 + 16);
                list.Synchronize(true);
                list.PrintCache(1 + 2 + 4 + 16);
                list.FlushCache();*/
                list.ChangeDirs(@"E:\temp\tmpmusic\root\");

                Console.WriteLine("\n*************** end ***************");
            }
            catch (Exception e)
            {
                System.Console.WriteLine("Main Error: {0}", e.Message);
            }
        }
    }
}
